package org.chen.processor;

import lombok.extern.slf4j.Slf4j;
import org.chen.domain.Article;
import org.chen.domain.CrawlerTask;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
public class ESPNPageProcessor implements PageProcessor {
    private final Site site = Site.me()
            .setRetryTimes(3)
            .setSleepTime(1000)
            .setTimeOut(10000)
            .setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

    private final CrawlerTask task;
    private final Set<String> processedUrls = Collections.synchronizedSet(new HashSet<>());
    private final Set<String> collectedLinks = Collections.synchronizedSet(new HashSet<>());
    private final AtomicInteger articleCount = new AtomicInteger(0);
    private final AtomicBoolean isCollectingLinks = new AtomicBoolean(true);

    private final Map<String, String> linkPatterns = new HashMap<>() {{
        put("nba", ".*/nba/.*");
        put("basketball", ".*/basketball/.*");
        put("betting", ".*/sports-betting/.*");
        put("rugby", ".*/rugby/.*");
        put("soccer", ".*/soccer/.*");
        put("transfers", ".*/soccer/transfers/.*");
    }};

    public ESPNPageProcessor(CrawlerTask task) {
        this.task = task;
    }

    @Override
    public void process(Page page) {
        String category = task.getCategory();

        // 如果已经达到目标文章数量，停止处理
        if (articleCount.get() >= task.getTargetCount()) {
            page.setSkip(true);
            return;
        }

        // 第一阶段：收集链接
        if (isCollectingLinks.get()) {
            collectLinks(page, category);
            return;
        }

        // 第二阶段：处理文章
        processArticle(page, category);

        // 检查是否需要重新收集链接
        checkAndResumeCollection(page);
    }

    private void checkAndResumeCollection(Page page) {
        // 如果还没达到目标数量，并且处理的URL数接近收集的链接数
        if (articleCount.get() < task.getTargetCount() &&
                processedUrls.size() >= collectedLinks.size() * 0.8) { // 当处理了80%的链接时就开始收集新的

            log.info("Processed {} articles but target is {}. Switching back to collection phase.",
                    articleCount.get(), task.getTargetCount());

            // 切换回收集模式
            isCollectingLinks.set(true);

            // 清除已收集的链接集合，准备收集新的
            collectedLinks.clear();

            // 添加新的起始URL到队列
            String newStartUrl = task.getStartUrl();
            if (!processedUrls.contains(newStartUrl)) {
                page.addTargetRequest(newStartUrl);
                log.info("Added new start URL for collection: {}", newStartUrl);
            }
        }
    }

    private void collectLinks(Page page, String category) {
        log.info("Collecting links from page: {}", page.getUrl());

        // 收集文章链接
        Set<String> newLinks = new HashSet<>(page.getHtml()
                .links()
                .regex(".*/story/.*")
                .all());

        // 使用分类特定的链接模式
        String linkPattern = linkPatterns.get(category);
        if (linkPattern != null) {
            newLinks.addAll(page.getHtml()
                    .links()
                    .regex(linkPattern)
                    .all());

            // 同时收集故事链接，但确保它们属于正确的分类
            newLinks.addAll(page.getHtml()
                    .links()
                    .regex(".*" + category + ".*/story/.*")
                    .all());
        }

        // 标准化和过滤链接
        Set<String> normalizedLinks = newLinks.stream()
                .map(link -> !link.startsWith("http") ? "https://www.espn.com" + link : link)
                .filter(link -> !collectedLinks.contains(link) && !processedUrls.contains(link))
                .filter(link -> {
                    if (!"transfers".equals(category)) {
                        return link.contains("/" + category + "/");
                    }
                    return link.contains("/");
                }) // 确保链接属于正确的分类
                .collect(Collectors.toSet());

        log.info("Found {} new unique {} links", normalizedLinks.size(), category);

        // 添加新链接到收集集合
        collectedLinks.addAll(normalizedLinks);

        log.info("Found {} new unique links, total collected: {}, target remaining: {}",
                normalizedLinks.size(), collectedLinks.size(),
                task.getTargetCount() - articleCount.get());

        // 如果收集够了足够的链接，切换到处理阶段
        if (collectedLinks.size() >= (task.getTargetCount() - articleCount.get()) * 1.2) { // 多收集20%的链接作为备用
            isCollectingLinks.set(false);
            log.info("Switching to article processing phase. Starting to process articles. " +
                    "Current count: {}, Target: {}", articleCount.get(), task.getTargetCount());

            // 添加收集到的链接到处理队列
            collectedLinks.stream()
                    .filter(link -> !processedUrls.contains(link))
                    .forEach(page::addTargetRequest);
        } else {
            // 如果还需要更多链接，继续收集
            normalizedLinks.forEach(page::addTargetRequest);
        }

        page.setSkip(true);
    }

    private void processArticle(Page page, String category) {
        String currentUrl = page.getUrl().toString();

        // 验证URL是否属于正确的分类
        if (!"transfers".equals(category)) {
            if (!currentUrl.contains("/" + category + "/")) {
                log.warn("Skipping article from wrong category: {}", currentUrl);
                page.setSkip(true);
                return;
            }
        }

        // 检查是否已处理过
        if (processedUrls.contains(currentUrl)) {
            page.setSkip(true);
            return;
        }

        try {
            String title = page.getHtml()
                    .xpath("//header[@class='article-header']/h1/text()")
                    .get();

            if (title == null || title.isEmpty()) {
                title = page.getHtml().css("h1", "text").get();
            }

            if (title == null || title.isEmpty()) {
                log.warn("No title found for page: {}", currentUrl);
                page.setSkip(true);
                return;
            }

            log.info("Processing article {}/{}: {}",
                    articleCount.get() + 1, task.getTargetCount(), title);

            // 获取段落
            List<String> paragraphs = page.getHtml()
                    .$("div.article-body p", "text")
                    .all();

            // 只获取用户指定数量的段落
            int paragraphCount = task.getParagraphCount() != null ? task.getParagraphCount() : 1;
            StringBuilder content = new StringBuilder();

            for (int i = 0; i < Math.min(paragraphCount, paragraphs.size()); i++) {
                if (i > 0) content.append("\n\n");
                content.append(paragraphs.get(i).trim());
            }

            if (content.length() <= 0){
                return;
            }

            Article article = new Article();
            article.setTitle(title);
            article.setDescription(content.toString());
            article.setUrl(currentUrl);
            article.setSource("espn");

            // 设置分类信息
            article.setCategoryId(task.getCategoryId());         // 从任务中获取分类ID
            article.setCategoryPath(task.getCategoryPath());     // 从任务中获取分类路径
            article.setCategory(category);
            article.setCreateTime(LocalDateTime.now());

            page.putField("article", article);
            processedUrls.add(currentUrl);
            articleCount.incrementAndGet();


            // 如果处理完指定数量的文章，切换回收集模式
            if (articleCount.get() >= task.getTargetCount()) {
                log.info("Reached target article count: {}", task.getTargetCount());
            } else if (articleCount.get() >= collectedLinks.size()) {
                // 如果处理完所有收集的链接但还没达到目标，切换回收集模式
                log.info("Processed all collected links but only got {} articles, switching back to collection phase",
                        articleCount.get());
                isCollectingLinks.set(true);
                collectedLinks.clear(); // 清除已收集的链接，准备收集新的
            }

        } catch (Exception e) {
            log.error("Error processing article: {}", e.getMessage(), e);
            page.setSkip(true);
        }
    }

    @Override
    public Site getSite() {
        return site;
    }
}